﻿namespace OrderServiceLevel0
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Mime;
    using System.Web;
    using System.Xml.Serialization;
    using log4net;
    using OrderServiceLevel0.Model;
    using OrderServiceLevel0.Repositories;

    public class OrderManagementService : BaseHttpHandler
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(OrderManagementService));
        private readonly Dictionary<string, Action<HttpContextBase>> dispatcher;
        private IRepository repository = new MemoryRepository();

        public OrderManagementService()
        {
            this.dispatcher = new Dictionary<string, Action<HttpContextBase>>();

            this.dispatcher.Add("/SubmitOrder", this.SubmitOrder);
            this.dispatcher.Add("/GetOrders", this.GetOrders);
            this.dispatcher.Add("/GetOrderDetails", this.GetOrderDetails);
            this.dispatcher.Add("/UpdateOrder", this.UpdateOrder);
            this.dispatcher.Add("/AddOrderItem", this.AddOrderItem);
            this.dispatcher.Add("/CancelOrder", this.CancelOrder);
        }

        public IRepository Respository
        {
            set
            {
                this.repository = value;
            }
        }

        public override void ProcessRequest(HttpContextBase context)
        {
            string action = context.Request.Path.Replace("/OrderServiceLevel0", string.Empty);

            if (this.dispatcher.ContainsKey(action))
            {
                this.dispatcher[action](context);
            }
            else
            {
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
            }
        }

        /// <remarks>
        ///  /OrderServiceLevel0/CancelOrder
        /// </remarks>
        private void CancelOrder(HttpContextBase context)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(Order));
                dynamic dynamicOrder = serializer.Deserialize(context.Request.InputStream);

                log.InfoFormat("[CancelOrder] OrderId: {0}", dynamicOrder.Id);

                this.repository.RemoveOrder(dynamicOrder.Id);

                context.Response.ContentType = MediaTypeNames.Text.Xml;
                context.Response.StatusCode = (int)HttpStatusCode.NoContent;
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        ///  /OrderServiceLevel0/AddOrderItem
        /// </remarks>
        private void AddOrderItem(HttpContextBase context)
        {
            try
            {
                Item item = new Item();
                XmlSerializer serializer = new XmlSerializer(typeof(Order));
                dynamic dynamicOrder = serializer.Deserialize(context.Request.InputStream);
                Order order = this.repository.RetrieveOrder(dynamicOrder.Id);

                item.Id = dynamicOrder.Items.Items[0].Id;
                item.Price = dynamicOrder.Items.Items[0].Price;
                item.Quantity = dynamicOrder.Items.Items[0].Quantity;

                order.AddItem(item);

                log.InfoFormat("[AddOrderItem] {0}", order);

                this.repository.UpdateOrder(order);

                context.Response.ContentType = MediaTypeNames.Text.Xml;
                context.Response.StatusCode = (int)HttpStatusCode.NoContent;
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        ///  /OrderServiceLevel0/UpdateOrder
        /// </remarks>
        private void UpdateOrder(HttpContextBase context)
        {
            try
            {
                Order order = new Order();
                Customer customer = new Customer();
                XmlSerializer serializer = new XmlSerializer(typeof(Order));
                dynamic dynamicOrder = serializer.Deserialize(context.Request.InputStream);

                customer.Email = dynamicOrder.Customer.Email;
                customer.Name = dynamicOrder.Customer.Name;

                order.Id = dynamicOrder.Id;
                order.Currency = dynamicOrder.Currency;
                order.Status = dynamicOrder.Status;
                order.Placed = dynamicOrder.Placed;
                order.Customer = customer;

                log.InfoFormat("[UpdateOrder] OrderId: {0}", order);

                this.repository.UpdateOrder(order);

                context.Response.ContentType = MediaTypeNames.Text.Xml;
                context.Response.StatusCode = (int)HttpStatusCode.OK;

                serializer.Serialize(context.Response.OutputStream, this.repository.RetrieveOrder(order.Id));
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        /// /OrderServiceLevel0/GetOrderDetails
        /// </remarks>
        private void GetOrderDetails(HttpContextBase context)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(Order));
                dynamic dynamicOrder = serializer.Deserialize(context.Request.InputStream);
                Order order = this.repository.RetrieveOrder(dynamicOrder.Id);

                context.Response.ContentType = MediaTypeNames.Text.Xml;
                context.Response.StatusCode = (int)HttpStatusCode.OK;

                log.InfoFormat("[GetOrderDetails]", dynamicOrder.Id);

                serializer.Serialize(context.Response.OutputStream, order);
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        /// /OrderServiceLevel0/GetOrders
        /// </remarks>
        private void GetOrders(HttpContextBase context)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(List<Order>));

                context.Response.ContentType = MediaTypeNames.Text.Xml;
                context.Response.StatusCode = (int)HttpStatusCode.OK;

                log.Info("[GetOrders]");

                serializer.Serialize(context.Response.OutputStream, this.repository.Orders);
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }

        /// <remarks>
        /// /OrderServiceLevel0/SubmitOrder
        /// </remarks>
        private void SubmitOrder(HttpContextBase context)
        {
            try
            {
                Order order = new Order();
                Customer customer = new Customer();
                XmlSerializer serializer = new XmlSerializer(typeof(Order));
                dynamic dynamicOrder = serializer.Deserialize(context.Request.InputStream);

                customer.Email = dynamicOrder.Customer.Email;
                customer.Name = dynamicOrder.Customer.Name;

                order.Id = dynamicOrder.Id;
                order.Currency = dynamicOrder.Currency;
                order.Status = dynamicOrder.Status;
                order.Placed = dynamicOrder.Placed;
                order.Customer = customer;

                log.InfoFormat("[SubmitOrder] {0}", order);

                this.repository.AddOrder(order);

                context.Response.ContentType = MediaTypeNames.Text.Xml;
                context.Response.StatusCode = (int)HttpStatusCode.Created;

                serializer.Serialize(context.Response.OutputStream, this.repository.RetrieveOrder(order.Id));
            }
            catch
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            }
        }
    }
}